import asyncio
import re
import os
import base64
import tempfile
from bilibili_api import video, Credential
from typing import Dict, List, Optional
import aiohttp
import cv2
from PIL import Image
import io
from config import Config


class BilibiliService:
    """B站视频服务类"""
    
    def __init__(self):
        self.credential = self._init_credential()

    def _init_credential(self) -> Optional[Credential]:
        """初始化B站登录凭据"""
        try:
            # 检查是否配置了核心登录凭据（BUVID3不是必需的）
            if all([
                Config.BILIBILI_SESSDATA,
                Config.BILIBILI_BILI_JCT,
                Config.BILIBILI_DEDEUSERID
            ]):
                credential = Credential(
                    sessdata=Config.BILIBILI_SESSDATA,
                    bili_jct=Config.BILIBILI_BILI_JCT,
                    buvid3=Config.BILIBILI_BUVID3 or "",  # BUVID3可以为空
                    dedeuserid=Config.BILIBILI_DEDEUSERID
                )
                print("[信息] 已加载B站登录凭据，将获取完整数据")
                return credential
            else:
                print("[信息] 未配置B站登录凭据，将获取有限的公开数据")
                return None
        except Exception as e:
            print(f"[警告] 初始化B站凭据失败: {e}")
            return None

    async def check_credential_valid(self) -> bool:
        """检查凭据是否有效"""
        if not self.credential:
            return False

        try:
            is_valid = await self.credential.check_valid()
            if not is_valid:
                print("[警告] B站登录凭据已失效")
                return False
            return True
        except Exception as e:
            print(f"[警告] 检查凭据有效性失败: {e}")
            return False

    def _calculate_optimal_frame_params(self, duration_seconds: int) -> tuple[int, int]:
        """根据视频时长智能计算最优的帧提取参数

        Args:
            duration_seconds: 视频时长（秒）

        Returns:
            tuple: (max_frames, interval_seconds)
        """
        # 视频长度分类（基于官方文档建议：短视频max_frames=8-16，fps=1-2）
        if duration_seconds <= 300:  # 5分钟以下 - 超短视频
            # 高密度采样，更多帧数，短间隔
            max_frames = min(16, max(8, duration_seconds // 10))  # 每10秒一帧，最多16帧
            interval = 8  # 8秒间隔，约等于fps=1.25
        elif duration_seconds <= 600:  # 5-10分钟 - 短视频
            # 中高密度采样
            max_frames = 14  # 固定14帧
            interval = 12  # 12秒间隔，约等于fps=1.67
        elif duration_seconds <= 1800:  # 10-30分钟 - 中等视频
            # 中等密度采样
            max_frames = 12  # 固定12帧
            interval = max(15, duration_seconds // 12)  # 15秒或更长间隔
        elif duration_seconds <= 3600:  # 30-60分钟 - 长视频
            # 低密度采样
            max_frames = 10  # 固定10帧
            interval = max(20, duration_seconds // 10)  # 20秒或更长间隔
        else:  # 60分钟以上 - 超长视频
            # 极低密度采样
            max_frames = 8  # 固定8帧
            interval = max(30, duration_seconds // 8)  # 30秒或更长间隔

        # 确保最小间隔为5秒，最大间隔为60秒
        interval = max(5, min(60, interval))

        print(f"[智能参数] 视频时长{duration_seconds}秒 → max_frames: {max_frames}, interval: {interval}秒")
        return max_frames, interval

    def _smart_sample_danmaku(self, danmaku_list: List, max_limit: int) -> List[str]:
        """智能采样弹幕，根据总量动态调整采样策略

        Args:
            danmaku_list: 原始弹幕列表
            max_limit: 最大限制数量

        Returns:
            采样后的弹幕文本列表
        """
        if not danmaku_list:
            return []

        total_count = len(danmaku_list)
        print(f"[调试] 弹幕智能采样 - 总量: {total_count}, 限制: {max_limit}")

        # 根据弹幕总量智能采样
        if total_count <= 200:
            # 少量弹幕，全部使用
            sampled = [d.text for d in danmaku_list]
            print(f"[调试] 少量弹幕({total_count}条)，全部使用")
        elif total_count <= 1000:
            # 中等数量，使用前30% + 中间40% + 后30%
            front_count = int(total_count * 0.3)
            middle_count = int(total_count * 0.4)
            back_count = total_count - front_count - middle_count

            front_danmaku = [d.text for d in danmaku_list[:front_count]]
            middle_danmaku = [d.text for d in danmaku_list[front_count:front_count + middle_count]]
            back_danmaku = [d.text for d in danmaku_list[front_count + middle_count:]]

            sampled = front_danmaku + middle_danmaku + back_danmaku
            print(f"[调试] 中等弹幕({total_count}条)，采样策略: 前{front_count}+中{middle_count}+后{back_count}={len(sampled)}")
        elif total_count <= 5000:
            # 大量弹幕，使用前20% + 均匀采样中间60% + 后20%
            front_count = int(total_count * 0.2)
            middle_count = int(total_count * 0.6)
            back_count = total_count - front_count - middle_count

            front_danmaku = [d.text for d in danmaku_list[:front_count]]

            # 中间部分均匀采样
            middle_part = danmaku_list[front_count:front_count + middle_count]
            middle_danmaku = [d.text for i, d in enumerate(middle_part)
                             if i % max(1, len(middle_part) // 500) == 0]  # 每500条取1条

            back_danmaku = [d.text for d in danmaku_list[front_count + middle_count:]]

            sampled = front_danmaku + middle_danmaku + back_danmaku
            print(f"[调试] 大量弹幕({total_count}条)，采样策略: 前{front_count}+中间{len(middle_danmaku)}+后{back_count}={len(sampled)}")
        else:
            # 超大量弹幕，使用前15% + 稀疏采样中间70% + 后15%
            front_count = int(total_count * 0.15)
            back_count = int(total_count * 0.15)
            middle_count = total_count - front_count - back_count

            front_danmaku = [d.text for d in danmaku_list[:front_count]]

            # 中间部分非常稀疏采样
            middle_part = danmaku_list[front_count:front_count + middle_count]
            middle_danmaku = [d.text for i, d in enumerate(middle_part)
                             if i % max(1, len(middle_part) // 1000) == 0]  # 每1000条取1条

            back_danmaku = [d.text for d in danmaku_list[front_count + middle_count:]]

            sampled = front_danmaku + middle_danmaku + back_danmaku
            print(f"[调试] 超大量弹幕({total_count}条)，采样策略: 前{front_count}+中间{len(middle_danmaku)}+后{back_count}={len(sampled)}")

        # 最终限制到合理数量
        if len(sampled) > max_limit:
            sampled = sampled[:max_limit]
            print(f"[调试] 最终限制到{max_limit}条")

        print(f"[信息] 弹幕采样完成: {total_count} → {len(sampled)} 条")
        return sampled
    
    @staticmethod
    def extract_bvid(url: str) -> Optional[str]:
        """从B站链接中提取BVID"""
        # 支持多种格式的B站链接
        patterns = [
            r'BV[a-zA-Z0-9]+',  # 直接的BVID
            r'bilibili\.com/video/(BV[a-zA-Z0-9]+)',  # 标准链接
            r'b23\.tv/(\w+)',  # 短链接（需要进一步处理）
        ]
        
        for pattern in patterns:
            match = re.search(pattern, url)
            if match:
                bvid = match.group(1) if len(match.groups()) > 0 else match.group(0)
                if bvid.startswith('BV'):
                    return bvid
        
        return None
    
    async def get_video_info(self, bvid: str) -> Dict:
        """获取视频基本信息"""
        try:
            v = video.Video(bvid=bvid, credential=self.credential)
            info = await v.get_info()
            
            return {
                'success': True,
                'data': {
                    'bvid': info.get('bvid'),
                    'title': info.get('title'),
                    'desc': info.get('desc'),
                    'duration': info.get('duration'),
                    'author': info.get('owner', {}).get('name'),
                    'view': info.get('stat', {}).get('view'),
                    'like': info.get('stat', {}).get('like'),
                    'cover': info.get('pic'),
                    'pubdate': info.get('pubdate'),
                }
            }
        except Exception as e:
            return {
                'success': False,
                'error': f'获取视频信息失败: {str(e)}'
            }
    
    async def get_video_subtitles(self, bvid: str) -> Dict:
        """获取视频字幕"""
        try:
            v = video.Video(bvid=bvid, credential=self.credential)
            
            # 获取视频字幕列表
            subtitle_info = await v.get_subtitle()
            
            if not subtitle_info or 'subtitles' not in subtitle_info:
                return {
                    'success': True,
                    'data': {
                        'has_subtitle': False,
                        'subtitles': []
                    }
                }
            
            subtitles_list = subtitle_info['subtitles']
            
            if not subtitles_list:
                return {
                    'success': True,
                    'data': {
                        'has_subtitle': False,
                        'subtitles': []
                    }
                }
            
            # 获取第一个字幕（通常是中文）
            subtitle_url = 'https:' + subtitles_list[0]['subtitle_url']
            
            # 下载字幕内容
            import aiohttp
            async with aiohttp.ClientSession() as session:
                async with session.get(subtitle_url) as resp:
                    subtitle_data = await resp.json()
            
            # 解析字幕内容
            subtitle_text = []
            for item in subtitle_data.get('body', []):
                subtitle_text.append(item.get('content', ''))
            
            return {
                'success': True,
                'data': {
                    'has_subtitle': True,
                    'subtitles': subtitle_text,
                    'full_text': '\n'.join(subtitle_text),
                    'language': subtitles_list[0].get('lan_doc', '中文')
                }
            }
        except Exception as e:
            return {
                'success': False,
                'error': f'获取字幕失败: {str(e)}'
            }
    
    async def get_video_danmaku(self, bvid: str, limit: int = 200) -> Dict:
        """获取视频弹幕（支持登录状态获取更多数据）"""
        try:
            v = video.Video(bvid=bvid, credential=self.credential)

            # 检查登录状态
            has_credential = await self.check_credential_valid()
            if has_credential:
                print("[信息] 使用登录状态获取弹幕数据")
                # 登录用户可以获取更多弹幕，但不超过200
                actual_limit = min(limit, 200)
            else:
                print("[信息] 未登录，仅获取公开弹幕数据")
                # 未登录用户限制弹幕数量
                actual_limit = min(limit, 100)

            # 获取视频分P信息
            pages = await v.get_pages()

            if not pages:
                return {
                    'success': False,
                    'error': '无法获取视频分P信息'
                }

            # 获取第一个分P的弹幕
            page_index = 0
            danmaku_list = await v.get_danmakus(page_index=page_index)

            # 智能采样弹幕
            danmaku_texts = self._smart_sample_danmaku(danmaku_list, actual_limit)

            # 如果弹幕数量不足且已登录，尝试获取历史弹幕
            if has_credential and len(danmaku_texts) < actual_limit // 2:
                try:
                    # 尝试获取更多历史弹幕
                    print("[信息] 尝试获取历史弹幕数据...")
                    # 注意：这里可能需要额外的API调用，当前先保持简单
                except Exception as e:
                    print(f"[警告] 获取历史弹幕失败: {e}")

            print(f"[信息] 获取到 {len(danmaku_texts)} 条弹幕（登录状态: {has_credential}）")

            return {
                'success': True,
                'data': {
                    'danmaku_count': len(danmaku_texts),
                    'danmakus': danmaku_texts,
                    'full_text': '\n'.join(danmaku_texts),
                    'has_credential': has_credential,
                    'is_limited': len(danmaku_list) > actual_limit
                }
            }
        except Exception as e:
            return {
                'success': False,
                'error': f'获取弹幕失败: {str(e)}'
            }
    
    async def get_video_download_url(self, bvid: str) -> Dict:
        """获取视频下载链接（支持DASH格式）"""
        try:
            v = video.Video(bvid=bvid, credential=self.credential)
            
            # 获取视频下载链接
            download_url_data = await v.get_download_url(page_index=0)
            
            if not download_url_data:
                return {
                    'success': False,
                    'error': '无法获取视频下载链接'
                }
            
            # 使用 VideoDownloadURLDataDetecter 来检测最佳流
            detecter = video.VideoDownloadURLDataDetecter(data=download_url_data)
            streams = detecter.detect_best_streams()
            
            if not streams:
                return {
                    'success': False,
                    'error': '无法检测到可用的视频流'
                }
            
            # 检查是 FLV/MP4 流还是 DASH 流（音视频分离）
            is_flv_mp4 = detecter.check_flv_mp4_stream()
            
            if is_flv_mp4:
                # FLV/MP4 流：音视频合一
                return {
                    'success': True,
                    'data': {
                        'video_url': streams[0].url,
                        'audio_url': None,
                        'is_dash': False,
                        'quality': download_url_data.get('quality', 0)
                    }
                }
            else:
                # DASH 流：音视频分离
                video_url = streams[0].url if len(streams) > 0 else None
                audio_url = streams[1].url if len(streams) > 1 else None
                
                if not video_url:
                    return {
                        'success': False,
                        'error': '无法获取视频流URL'
                    }
                
                return {
                    'success': True,
                    'data': {
                        'video_url': video_url,
                        'audio_url': audio_url,
                        'is_dash': True,
                        'quality': download_url_data.get('quality', 0)
                    }
                }
        except Exception as e:
            return {
                'success': False,
                'error': f'获取视频下载链接失败: {str(e)}'
            }
    
    async def extract_video_frames(self, bvid: str, max_frames: Optional[int] = None, interval: Optional[int] = None) -> Dict:
        """智能提取视频关键帧

        Args:
            bvid: 视频BV号
            max_frames: 最大提取帧数（可选，如果不提供则根据视频时长智能计算）
            interval: 提取间隔（秒）（可选，如果不提供则根据视频时长智能计算）

        Returns:
            包含base64编码的图像列表
        """
        temp_video_path = None
        try:
            print(f"[调试] 开始提取视频帧 - BVID: {bvid}")

            # 首先获取视频基本信息以确定时长
            video_info_result = await self.get_video_info(bvid)
            if not video_info_result['success']:
                return {
                    'success': False,
                    'error': f'无法获取视频信息: {video_info_result["error"]}'
                }

            # 获取视频时长（秒）
            duration = video_info_result['data'].get('duration', 0)
            print(f"[调试] 视频时长: {duration}秒")

            # 智能计算最优参数
            if max_frames is None or interval is None:
                max_frames, interval = self._calculate_optimal_frame_params(duration)
                print(f"[调试] 智能计算参数 - max_frames: {max_frames}, interval: {interval}秒")

            # 获取视频下载链接
            download_result = await self.get_video_download_url(bvid)
            if not download_result['success']:
                return download_result
            
            video_url = download_result['data']['video_url']
            is_dash = download_result['data'].get('is_dash', False)
            
            print(f"[调试] 视频格式: {'DASH (音视频分离)' if is_dash else 'FLV/MP4 (音视频合一)'}")
            print(f"[调试] 获取到视频URL: {video_url[:80]}...")
            
            # 下载视频到临时文件
            # DASH 格式使用 .m4s 扩展名，其他格式使用 .mp4
            file_ext = '.m4s' if is_dash else '.mp4'
            temp_video_path = os.path.join(tempfile.gettempdir(), f'{bvid}_video{file_ext}')
            
            # 使用aiohttp下载视频（带正确的headers）
            headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
                'Referer': 'https://www.bilibili.com',
                'Accept': '*/*',
                'Accept-Encoding': 'identity',
                'Range': 'bytes=0-'  # 支持断点续传
            }
            
            print(f"[调试] 开始下载视频流...")
            async with aiohttp.ClientSession() as session:
                async with session.get(video_url, headers=headers) as resp:
                    if resp.status not in [200, 206]:  # 206 是部分内容响应
                        return {
                            'success': False,
                            'error': f'下载视频失败: HTTP {resp.status}'
                        }
                    
                    # 保存视频文件
                    total_size = resp.content_length or 0
                    downloaded = 0
                    with open(temp_video_path, 'wb') as f:
                        while True:
                            chunk = await resp.content.read(1024 * 1024)  # 1MB chunks
                            if not chunk:
                                break
                            f.write(chunk)
                            downloaded += len(chunk)
                            if total_size > 0:
                                percent = (downloaded / total_size) * 100
                                print(f"[调试] 下载进度: {percent:.1f}% ({downloaded}/{total_size} bytes)", end='\r')
            
            print(f"\n[调试] 视频下载完成: {temp_video_path} (大小: {os.path.getsize(temp_video_path)} bytes)")
            
            # 使用OpenCV提取帧
            cap = cv2.VideoCapture(temp_video_path)
            
            # 检查视频是否成功打开
            if not cap.isOpened():
                return {
                    'success': False,
                    'error': f'无法打开视频文件，可能是格式不支持或文件损坏'
                }
            
            fps = cap.get(cv2.CAP_PROP_FPS)
            total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
            duration = total_frames / fps if fps > 0 else 0
            
            print(f"[调试] 视频信息 - FPS: {fps}, 总帧数: {total_frames}, 时长: {duration}秒")
            
            # 如果无法获取视频信息，尝试读取一帧来验证
            if fps == 0 or total_frames == 0:
                print(f"[警告] 无法获取视频元数据，尝试读取帧...")
                ret, test_frame = cap.read()
                if not ret:
                    cap.release()
                    return {
                        'success': False,
                        'error': '无法读取视频帧，视频可能已损坏'
                    }
                # 重新打开视频
                cap.release()
                cap = cv2.VideoCapture(temp_video_path)
            
            frames_base64 = []
            frame_timestamps = []
            
            # 计算提取帧的时间点
            frame_interval = int(fps * interval) if fps > 0 else 1
            current_frame = 0
            
            while len(frames_base64) < max_frames and current_frame < total_frames:
                cap.set(cv2.CAP_PROP_POS_FRAMES, current_frame)
                ret, frame = cap.read()
                
                if not ret:
                    break
                
                # 极致优化：更小的图像尺寸和更强的压缩
                height, width = frame.shape[:2]
                target_width = 320  # 进一步降低到320px，大幅减少数据量
                if width > target_width:
                    scale = target_width / width
                    new_width = target_width
                    new_height = int(height * scale)
                    frame = cv2.resize(frame, (new_width, new_height))

                # 极强的JPEG压缩（质量25，最小化文件大小）
                _, buffer = cv2.imencode('.jpg', frame, [cv2.IMWRITE_JPEG_QUALITY, 25])
                
                # 转换为base64
                frame_base64 = base64.b64encode(buffer).decode('utf-8')
                frames_base64.append(frame_base64)
                
                timestamp = current_frame / fps if fps > 0 else 0
                frame_timestamps.append(timestamp)
                
                print(f"[调试] 提取第 {len(frames_base64)} 帧 - 时间: {timestamp:.1f}秒")
                
                current_frame += frame_interval
            
            cap.release()
            
            print(f"[调试] 成功提取 {len(frames_base64)} 帧")
            
            return {
                'success': True,
                'data': {
                    'frames': frames_base64,
                    'timestamps': frame_timestamps,
                    'frame_count': len(frames_base64),
                    'video_duration': duration,
                    'video_fps': fps
                }
            }
        
        except Exception as e:
            print(f"[错误] 提取视频帧失败: {str(e)}")
            import traceback
            traceback.print_exc()
            return {
                'success': False,
                'error': f'提取视频帧失败: {str(e)}'
            }
        
        finally:
            # 清理临时文件
            if temp_video_path and os.path.exists(temp_video_path):
                try:
                    os.remove(temp_video_path)
                    print(f"[调试] 已删除临时文件: {temp_video_path}")
                except Exception as e:
                    print(f"[警告] 删除临时文件失败: {str(e)}")
    
    def _smart_sample_comments(self, comments_list: List, target_count: int) -> List:
        """智能采样评论，优先获取最早和最新的评论

        Args:
            comments_list: 原始评论列表（按时间顺序）
            target_count: 目标采样数量

        Returns:
            采样后的评论列表
        """
        if not comments_list:
            return []

        total_count = len(comments_list)
        print(f"[调试] 评论智能采样 - 总量: {total_count}, 目标: {target_count}")

        if total_count <= target_count:
            # 如果评论数量不超过目标，全部使用
            sampled = comments_list
            print(f"[调试] 评论数量({total_count})未超过目标({target_count})，全部使用")
        else:
            # 智能采样：前40% + 中间20% + 后40%
            front_count = int(target_count * 0.4)
            back_count = int(target_count * 0.4)
            middle_count = target_count - front_count - back_count

            # 前40%：最早的评论
            front_comments = comments_list[:front_count]

            # 后40%：最新的评论
            back_comments = comments_list[-back_count:] if back_count > 0 else []

            # 中间20%：从中间部分均匀采样
            if middle_count > 0:
                middle_start = front_count
                middle_end = total_count - back_count
                middle_part = comments_list[middle_start:middle_end]

                # 均匀采样中间部分
                if len(middle_part) > middle_count:
                    step = len(middle_part) / middle_count
                    middle_comments = [middle_part[int(i * step)] for i in range(middle_count)]
                else:
                    middle_comments = middle_part
            else:
                middle_comments = []

            sampled = front_comments + middle_comments + back_comments
            print(f"[调试] 评论采样策略: 前{front_count}+中{len(middle_comments)}+后{back_count}={len(sampled)}")

        print(f"[信息] 评论采样完成: {total_count} → {len(sampled)} 条")
        return sampled

    async def get_video_comments(self, bvid: str, max_pages: int = 10, target_count: int = 200) -> Dict:
        """获取视频评论（支持登录状态获取更多数据）

        Args:
            bvid: 视频BV号
            max_pages: 最多获取页数
            target_count: 目标评论数量（智能采样）

        Returns:
            评论数据字典
        """
        try:
            from bilibili_api import comment

            v = video.Video(bvid=bvid, credential=self.credential)
            info = await v.get_info()
            aid = info.get('aid')

            if not aid:
                return {
                    'success': False,
                    'error': '无法获取视频aid'
                }

            # 检查登录状态
            has_credential = await self.check_credential_valid()
            if has_credential:
                print("[信息] 使用登录状态获取评论数据")
                actual_max_pages = max_pages
                actual_target = target_count
            else:
                print("[信息] 未登录，仅获取公开评论数据")
                actual_max_pages = min(max_pages, 5)  # 未登录限制页数，但适当增加
                actual_target = min(target_count, 100)  # 未登录限制目标数量

            print(f"[调试] 开始获取评论 - aid: {aid}, 最多{actual_max_pages}页，目标{actual_target}条")

            comments_list = []
            page = 1
            pag = ""
            seen_rpids = set()  # 用于去重

            # 先获取基础评论数据，可能超过目标数量
            while page <= actual_max_pages:
                try:
                    c = await comment.get_comments_lazy(
                        aid,
                        comment.CommentResourceType.VIDEO,
                        offset=pag
                    )

                    pag = c.get("cursor", {}).get("pagination_reply", {}).get("next_offset", "")
                    replies = c.get('replies', [])

                    if not replies:
                        break

                    # 去重并添加
                    for reply in replies:
                        rpid = reply.get('rpid')
                        if rpid and rpid not in seen_rpids:
                            seen_rpids.add(rpid)
                            comments_list.append(reply)

                    page += 1

                    # 如果没有下一页标记，退出
                    if not pag:
                        break

                    # 如果已经获取足够的评论，可以提前退出（但至少获取几页以确保有时间分布）
                    if len(comments_list) >= actual_target * 2 and page >= 3:
                        print(f"[调试] 已获取足够评论({len(comments_list)}条)，提前结束")
                        break

                except Exception as e:
                    print(f"[警告] 获取第{page}页评论失败: {e}")
                    break

            # 智能采样评论
            sampled_comments = self._smart_sample_comments(comments_list, actual_target)

            # 处理评论数据
            processed_comments = []
            for cmt in sampled_comments:
                member = cmt.get('member', {})
                content = cmt.get('content', {})

                # 获取用户等级（登录用户可见）
                level_info = member.get('level_info', {})
                user_level = level_info.get('current_level', 0) if has_credential else 0

                processed_comments.append({
                    'username': member.get('uname', '未知用户'),
                    'message': content.get('message', ''),
                    'like': cmt.get('like', 0),
                    'reply_count': cmt.get('rcount', 0),
                    'time': cmt.get('ctime', 0),
                    'user_level': user_level,
                    'mid': member.get('mid', ''),
                    'avatar': member.get('avatar', ''),
                    'sex': member.get('sex', '未知') if has_credential else '未知'
                })

            print(f"[信息] 最终获取到 {len(processed_comments)} 条评论（登录状态: {has_credential}）")

            return {
                'success': True,
                'data': {
                    'comments': processed_comments,
                    'total_count': len(processed_comments),
                    'original_count': len(comments_list),  # 原始获取数量
                    'has_credential': has_credential,
                    'max_pages_reached': page > actual_max_pages and pag != "",
                    'sampling_used': len(comments_list) > actual_target  # 是否使用了采样
                }
            }
        except Exception as e:
            print(f"[错误] 获取评论失败: {str(e)}")
            import traceback
            traceback.print_exc()
            return {
                'success': False,
                'error': f'获取评论失败: {str(e)}'
            }
    
    async def get_video_stats(self, bvid: str) -> Dict:
        """获取视频统计信息（在线人数等）
        
        Args:
            bvid: 视频BV号
        
        Returns:
            统计数据字典
        """
        try:
            v = video.Video(bvid=bvid, credential=self.credential)
            
            # 获取基本信息
            info = await v.get_info()
            stats = info.get('stat', {})
            
            # 尝试获取在线人数（可能失败）
            online_info = None
            try:
                online = await v.get_online()
                online_info = {
                    'total': online.get('total', 0),
                    'web_count': online.get('count', 0)
                }
            except Exception as e:
                print(f"[警告] 获取在线人数失败: {e}")
            
            return {
                'success': True,
                'data': {
                    'view': stats.get('view', 0),
                    'like': stats.get('like', 0),
                    'coin': stats.get('coin', 0),
                    'favorite': stats.get('favorite', 0),
                    'share': stats.get('share', 0),
                    'danmaku': stats.get('danmaku', 0),
                    'reply': stats.get('reply', 0),
                    'online': online_info
                }
            }
        except Exception as e:
            return {
                'success': False,
                'error': f'获取统计信息失败: {str(e)}'
            }


def run_async(coro):
    """运行异步函数的辅助函数"""
    try:
        loop = asyncio.get_event_loop()
    except RuntimeError:
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
    
    return loop.run_until_complete(coro)

